home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Graphics 2D / Color Marquee / RedAnts.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  16.5 KB  |  699 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        RedAnts.c
  3.  
  4.     Contains:    This is a very basic snippet to illustrate how to implement a marquee.
  5.     
  6.                 there are two good references that cover this stuff.  Macintosh Programming Fundamentals
  7.                 by Knaster and Rollin, and Programming QuickDraw by Surovell, Hall and Othmer.  Both these
  8.                 works are published by addison wesley and both have sample code.
  9.     
  10.                  What we do here is track the mouse.  Periodically during tracking, and after we finish, we
  11.                 animate the selection rectangle.  We do this by working on a pattern, gMarqueePattern, shifting
  12.                 and rotating each row in the pattern, and setting this as the current pattern to use with the 
  13.                 call to frame rect.
  14.     
  15.                 For added spice we set the foreground color to red, this draws the marquee in the red color.
  16.  
  17.     Written by: Nick Thompson    
  18.  
  19.     Copyright:    Copyright © 1994-1999 by Apple Computer, Inc., All Rights Reserved.
  20.  
  21.                 You may incorporate this Apple sample source code into your program(s) without
  22.                 restriction. This Apple sample source code has been provided "AS IS" and the
  23.                 responsibility for its operation is yours. You are not permitted to redistribute
  24.                 this Apple sample source code as "Apple sample source code" after having made
  25.                 changes. If you're going to re-distribute the source, we require that you make
  26.                 it clear in the source that the code was descended from Apple sample source
  27.                 code, but that you've made changes.
  28.  
  29.     Change History (most recent first):
  30.                 7/8/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  31.                 4/21/94        nick    added facility to show a pict file and draw the marquee over that
  32.                                     this allows a demo of how to do the updating in the mouse tracker
  33.                                     routine.
  34.                 
  35.  
  36. */
  37.  
  38. #include <QuickDraw.h>
  39. #include <Palettes.h>
  40. #include <menus.h>
  41. #include <PictUtils.h>
  42. #include <QDOffScreen.h>
  43. #include <Windows.h>
  44. #include <Dialogs.h>
  45. #include <Fonts.h>
  46. #include <TextEdit.h>
  47. #include <Menus.h>
  48. #include <DiskInit.h>
  49. #include <StandardFile.h>
  50. #include <Devices.h>
  51.  
  52.  
  53. #define HiWrd(aLong)    (((aLong) >> 16) & 0xFFFF)
  54. #define LoWrd(aLong)    ((aLong) & 0xFFFF)
  55.  
  56. const RGBColor    kRGBBlack = {0, 0, 0};
  57. const RGBColor    kRGBWhite = {0xFFFF, 0xFFFF, 0xFFFF};
  58.  
  59. const char kEnter    = 0x03 ;
  60. const char kReturn    = 0x0D ;
  61. const char kEscape    = 0x1B ;
  62. const char kPeriod    = '.' ;
  63.  
  64.  
  65. typedef struct {
  66.     WindowRecord    theWindow ;        // the window
  67.     Rect            selRect ;        // the current selection rect in the window
  68. } MyWindow, *MyWindowPtr ;
  69.  
  70. enum {
  71.     mApple = 128,
  72.     mFile,
  73.     mPalette
  74. } ;
  75.  
  76. enum {
  77.     iAbout = 1
  78. } ;
  79. enum {
  80.     iOpen = 1,
  81.     iClose,
  82.     iUnused1,
  83.     iQuit = 4
  84. } ;
  85.  
  86. enum {
  87.     iUsePictPalette = 1
  88. } ;
  89.  
  90. static Point gStaggerPos = {50,50} ;
  91. static Boolean gUsePictPalette = true ;
  92. Boolean        gQuitFlag = false ;             // set to true to quit the application
  93. Rect        gLastRect = { 0, 0, 0, 0 } ;    // the last one we drew (used to clean up and for the marquee)
  94. long        gLastAnim ;
  95.  
  96. // pattern used for the marquee 
  97. // translate this to binary to see it!!
  98.  
  99. Pattern       gMarqueePattern = { 0x1f ,        // 00011111
  100.                                     0x3e ,        // 00111110
  101.                                     0x7c ,        // 01111100
  102.                                     0xf8 ,        // 11111000
  103.                                     0xf1 ,        // 11110001
  104.                                     0xe3 ,        // 11100011
  105.                                     0xc7 ,        // 11000111
  106.                                     0x8f } ;    // 10001111
  107.                                     
  108.  
  109. const    int    kTimeToAnimate = 1 ;        
  110.  
  111.                     
  112. void main( void ) ;
  113. void MainEventLoop( void ) ;
  114. void TrackMouse( Point    Anchor, WindowPtr theWindow )  ;
  115. Rect *CheckRect( Rect *theRect ) ;
  116. void    AnimateMarquee( Rect *theSelectionRect, WindowPtr whichWindow, Boolean mustDraw ) ;
  117. void InitToolbox( void ) ;
  118. void HandleKeyPress(EventRecord *event) ;
  119. void HandleMenuCommand(long menuResult) ;
  120. PicHandle DoReadPICT( short theRef, OSErr *theErr ) ;
  121. void AdjustMenus( void ) ;
  122. OSErr DoCreateWindow( PicHandle thePicture ) ;
  123. void UpdateWindow( WindowPtr theWindow, Rect *refreshArea ) ;
  124. pascal Boolean OurFilter(DialogPtr dlg, EventRecord *event, short *itemHit) ;
  125. void    FlashDialogItem(DialogPtr dlg, short itemToFlash);
  126.  
  127.  
  128. void main( void )
  129. {
  130.     InitToolbox() ;
  131.     
  132.     MainEventLoop();
  133. }
  134.  
  135.  
  136.  
  137. void InitToolbox()
  138. {
  139.     Handle        menuBar = nil;
  140.  
  141.  
  142.     InitGraf((Ptr) &qd.thePort);
  143.     InitFonts();
  144.     InitWindows();
  145.     InitMenus();
  146.     TEInit();
  147.     InitDialogs(0L);
  148.     InitCursor();
  149.  
  150.     // initialize application globals
  151.     
  152.     gQuitFlag = false;
  153.     
  154.     
  155.     menuBar = GetNewMBar(128);                // Read menus into menu bar, MBAR res id is 128
  156.     
  157.     if ( menuBar == nil )
  158.          ExitToShell();                        // if we dont have it then quit - your app 
  159.                                              // needs a dialog here
  160.  
  161.     SetMenuBar(menuBar);                    // Install menus
  162.     DisposeHandle(menuBar);
  163.     
  164.     AppendResMenu(GetMenuHandle(mApple), 'DRVR');    // Add DA names to Apple menu, ID 128
  165.  
  166.     DrawMenuBar();
  167. }
  168.  
  169.  
  170. void MainEventLoop()
  171. {
  172.     EventRecord     event;
  173. //    WindowPtr       window;
  174.     short           thePart;
  175.     Rect            screenRect;
  176.     Point            aPoint = {100, 100};
  177.     Rect             refreshArea ;
  178.     MyWindowPtr        window ;
  179.     
  180.     
  181.     while( !gQuitFlag )
  182.     {
  183.         WaitNextEvent( everyEvent, &event, 0, nil ) ;
  184.         AdjustMenus() ;
  185.  
  186.         switch (event.what) {
  187.         
  188.             default:
  189.                 if(( window = (MyWindowPtr)FrontWindow()) != nil ) {
  190.                     SetPort((WindowPtr)window) ;
  191.                      AnimateMarquee( CheckRect( &(((MyWindowPtr)window)->selRect) ), (WindowPtr)window, false ) ;
  192.                 }
  193.                 break ;
  194.                 
  195.             case mouseDown:
  196.             
  197.                 thePart = FindWindow( event.where,((WindowPtr *) &window) );
  198.                 
  199.                 switch( thePart ) {
  200.                     case inMenuBar: 
  201.                         HandleMenuCommand(MenuSelect(event.where));
  202.                         break;
  203.                     
  204.                     case inDrag:
  205.                 
  206.                         screenRect = (**GetGrayRgn()).rgnBBox;
  207.                         DragWindow( (WindowPtr)window, event.where, &screenRect );
  208.                         break ;
  209.                 
  210.                     case inContent:
  211.                 
  212.                         if ((WindowPtr)window != FrontWindow())
  213.                             SelectWindow( (WindowPtr)window );
  214.                         else {
  215.                             GlobalToLocal( &event.where ) ;
  216.                             TrackMouse( event.where, (WindowPtr)window ) ;
  217.                         }
  218.  
  219.                         break ;
  220.                 
  221.                     case inGoAway:
  222.                         if (TrackGoAway( (WindowPtr)window, event.where )) {
  223.                         
  224.                             // lose the GWorld
  225.                             DisposeGWorld((GWorldPtr)GetWRefCon((WindowPtr)window)) ;
  226.                             
  227.                             // lose the window
  228.                             DisposeWindow ( (WindowPtr)window );
  229.                         }
  230.                         break ;
  231.                         
  232.                     default:
  233.                         break ;
  234.                 }
  235.                 break ;
  236.                         
  237.                     
  238.             case updateEvt:
  239.             
  240.                 window = (MyWindowPtr)event.message;
  241.                 
  242.                 BeginUpdate( (WindowPtr)window );
  243.                 
  244.                 refreshArea = ((**(window->theWindow.port.visRgn)).rgnBBox);
  245.                 
  246.                 UpdateWindow( (WindowPtr)window, &refreshArea ) ;
  247.  
  248.                 EndUpdate( (WindowPtr)window );
  249.                 break ;
  250.                 
  251.             case keyDown:
  252.             case autoKey:
  253.                 HandleKeyPress(&event);
  254.                 break;
  255.                 
  256.             case diskEvt:
  257.                 if ( HiWrd(event.message) != noErr ) 
  258.                     (void) DIBadMount(aPoint, event.message);
  259.                 break;
  260.                 
  261.             case osEvt:
  262.             case activateEvt:
  263.                 break;
  264.  
  265.  
  266.         }
  267.     }
  268. }
  269.  
  270.  
  271. void HandleKeyPress(EventRecord *event)
  272. {
  273.     char    key;
  274.  
  275.     key = event->message & charCodeMask;
  276.     
  277.     // just check to see if we want to quit...
  278.     
  279.     if ( event->modifiers & cmdKey ) {        /* Command key down? */
  280.         HandleMenuCommand(MenuKey(key));
  281.     } 
  282. }
  283.  
  284.  
  285. void HandleMenuCommand(long menuResult)
  286. {
  287.     short        menuID;
  288.     short        menuItem;
  289.     Str255        daName;
  290.     DialogPtr    theDialog ; 
  291.     short        itemHit ;
  292.     SFTypeList    myTypes = { 'PICT' } ;
  293.     PicHandle    thePicture ;
  294.     OSErr        err ;
  295.     short        theRef ;
  296.     
  297.     StandardFileReply    theSFReply ;
  298.  
  299.     menuID = HiWrd(menuResult);
  300.     menuItem = LoWrd(menuResult);
  301.     switch ( menuID ) {
  302.         case mApple:
  303.             switch ( menuItem ) {
  304.                 case iAbout:
  305.                     theDialog = GetNewDialog ( 128, nil, (WindowPtr)-1 );
  306.                     do {
  307.                         ModalDialog ( NewModalFilterProc(OurFilter), &itemHit );
  308.                     } while( itemHit != ok ) ;
  309.                     DisposeDialog ( theDialog );
  310.                     break;
  311.                     
  312.                 default:
  313.                     GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
  314.                     (void) OpenDeskAcc(daName);
  315.                     break;
  316.             }
  317.             break;
  318.         case mFile:
  319.             switch ( menuItem ) {
  320.                 case iOpen:
  321.                     // Get the file name to open
  322.                     StandardGetFile( nil, 1, myTypes, &theSFReply ) ;
  323.                     
  324.                     // did the user cancel?
  325.                     if(!theSFReply.sfGood)
  326.                         break ;
  327.                     
  328.                     // open the file
  329.                     err = FSpOpenDF( &theSFReply.sfFile, fsRdPerm, &theRef ) ;
  330.                     
  331.                     if( err != noErr )
  332.                         break ;     // should handle this properly
  333.                         
  334.                     thePicture = DoReadPICT( theRef, &err ) ;
  335.                     
  336.                     if( err != noErr )
  337.                         break ;     // should handle this properly
  338.                 
  339.                     // display the contents
  340.                     err = DoCreateWindow( thePicture ) ;
  341.                     
  342.                     break ;
  343.                     
  344.                 case iClose:
  345.                     DisposeWindow ( FrontWindow() );
  346.                     break ;
  347.                 case iQuit:
  348.                     gQuitFlag = true;
  349.                     break;
  350.             }
  351.             break;
  352.             
  353.         case mPalette:
  354.             switch ( menuItem ) {
  355.                 case iUsePictPalette :
  356.                     // toggle the check mark and the global boolean
  357.                     gUsePictPalette = !gUsePictPalette ;
  358.                     CheckItem ( GetMenuHandle ( mPalette ), iUsePictPalette, gUsePictPalette );
  359.                     break ;
  360.             }
  361.             break ;
  362.     }
  363.     HiliteMenu(0);        // Unhighlight whatever MenuSelect or MenuKey hilited
  364. }
  365.  
  366. void    FlashDialogItem(DialogPtr dlg, short itemToFlash)
  367. {
  368.     short    iKind;
  369.     Handle    iHandle;
  370.     Rect    iRect;
  371.     unsigned long    ignored;
  372.  
  373.     GetDialogItem(dlg, itemToFlash, &iKind, &iHandle, &iRect);
  374.     HiliteControl((ControlHandle) iHandle, 1);
  375.     Delay(8, &ignored);
  376.     HiliteControl((ControlHandle) iHandle, 0);
  377. }
  378.  
  379.  
  380. pascal Boolean OurFilter(DialogPtr dlg, EventRecord *event, short *itemHit)
  381. {
  382.     short    iKind;
  383.     Handle    iHandle;
  384.     Rect    iRect;
  385.     char    key;
  386.     short    radius;
  387.  
  388.     switch (event->what) {
  389.  
  390.         case nullEvent:
  391.             break;
  392.  
  393.         case keyDown:
  394.         case autoKey:
  395.             key = event->message & charCodeMask;
  396.             if (event->modifiers & cmdKey) {        /* Command key down */
  397.                 if (key == kPeriod) {
  398.                     *itemHit = ok;
  399.                     FlashDialogItem(dlg, *itemHit);
  400.                 }
  401.                 return true;            /* This says we handle ALL command keys */
  402.             } else {
  403.                 if ((key == kReturn) || (key == kEnter)) {
  404.                     *itemHit = ok;
  405.                     FlashDialogItem(dlg, *itemHit);
  406.                     return true;
  407.                 }
  408.                 if (key == kEscape) {
  409.                     *itemHit = ok;
  410.                     FlashDialogItem(dlg, *itemHit);
  411.                     return true;
  412.                 }
  413.             }
  414.             return false;
  415.  
  416.         case updateEvt:
  417.             SetPort(dlg);
  418.                 
  419.             GetDialogItem(dlg, ok, &iKind, &iHandle, &iRect);            
  420.             InsetRect(&iRect, -4, -4);
  421.             radius = (iRect.bottom - iRect.top) / 2;
  422.             if (radius < 16)
  423.                 radius = 16;
  424.                 
  425.             PenSize(3,3);
  426.             FrameRoundRect(&iRect, radius, radius);
  427.             PenNormal();
  428.  
  429.  
  430.             return false;
  431.  
  432.         default:
  433.             return false;
  434.     }
  435.         return false;
  436. }
  437.  
  438.  
  439. void AdjustMenus( void ) 
  440. {
  441.     WindowPtr    theWindow ;
  442.     theWindow = FrontWindow() ;
  443.     if( theWindow != nil ) {
  444.         EnableItem ( GetMenuHandle ( mFile ), iClose );
  445.     }
  446.     else {
  447.         DisableItem ( GetMenuHandle ( mFile ), iClose );
  448.     }
  449.     // make sure the check marks are correct
  450.     CheckItem ( GetMenuHandle ( mPalette ), iUsePictPalette, gUsePictPalette );
  451. }
  452.  
  453. PicHandle DoReadPICT( short theRef, OSErr *theErr ) 
  454. {
  455.     long        theFileSize ;
  456.     PicHandle    thePicture ;
  457.     
  458.     // pict files have a 512 byte header at the front - we dont care about this
  459.     // we can find the size of the pict by subtracting 512 bytes from the length
  460.     // of the file.  We then want to resize the handle to that and read the data
  461.     // into the resized handle.
  462.     
  463.     if(( *theErr = GetEOF( theRef, &theFileSize )) != noErr ) {
  464.         FSClose( theRef ) ;
  465.         return nil ; 
  466.     }
  467.     
  468.     if(( *theErr = SetFPos( theRef, fsFromStart, 512)) != noErr ) {
  469.         FSClose( theRef ) ;
  470.         return nil ; 
  471.     }
  472.  
  473.     theFileSize -= 512 ;
  474.     
  475.     thePicture = (PicHandle)NewHandle( theFileSize ) ;
  476.     if( thePicture == nil ) {
  477.         FSClose( theRef ) ;
  478.         *theErr = MemError() ;
  479.         return nil ;         // what ever the mem manager error was
  480.     }
  481.     
  482.     HLock( (Handle)thePicture ) ;
  483.     *theErr = FSRead( theRef, &theFileSize, (Ptr)*thePicture ) ;
  484.     HUnlock(  (Handle)thePicture ) ;
  485.     
  486.     if( *theErr != noErr ) {
  487.         FSClose( theRef ) ;
  488.         return nil ; 
  489.     }
  490.  
  491.     return thePicture ;    
  492. }
  493.  
  494. OSErr DoCreateWindow( PicHandle thePicture )
  495. {
  496.  
  497.     Rect        theRect ;
  498.     OSErr        theErr ;
  499.     GWorldPtr    theNewWorld ;
  500.     CGrafPtr    savedPort ;
  501.     GDHandle    oldDevice ;
  502.     MyWindowPtr    myWindowPtr ;
  503.     Rect        selectionRect  = {0,0,0,0} ;
  504.     
  505.     PictInfo        thePictInfo ;
  506.     PaletteHandle    thePictPalette = nil ;
  507.     CTabHandle        thePictCTab = nil ;
  508.     
  509.     // make an offscreen environment and image the pict into this
  510.     // Make a window the size of the pict
  511.     // store a reference to the GWorld in the Refcon of the window
  512.     // invalidate the window content area.
  513.     
  514.     theRect.top = (**thePicture).picFrame.top ;
  515.     theRect.left = (**thePicture).picFrame.left ;
  516.     theRect.bottom = (**thePicture).picFrame.bottom ;
  517.     theRect.right = (**thePicture).picFrame.right ;
  518.     
  519.     // to we want to attempt to sample the picture... 
  520.     if( gUsePictPalette ) {
  521.     
  522.         // use the picture utilities to get the palette for the window
  523.         theErr = GetPictInfo( thePicture, &thePictInfo, returnColorTable, 256, systemMethod, 0) ;
  524.         
  525.         // set up the palette and color table for later use
  526.         thePictPalette = NewPalette( 256, thePictInfo.theColorTable, pmTolerant, 0x5000 ) ;
  527.         thePictCTab = thePictInfo.theColorTable ;
  528.     }
  529.     
  530.     // we are going to cheat a bit here, I only want to deal with
  531.     // 8 bit images for the purposes of this snippet
  532.     theErr = NewGWorld( &theNewWorld, 8, &theRect, thePictCTab, nil, 0L ) ;
  533.     
  534.     if( theErr != noErr ) 
  535.         return theErr ;
  536.     
  537.     // save the world
  538.     GetGWorld( &savedPort, &oldDevice ) ;
  539.     SetGWorld( theNewWorld, nil ) ;
  540.     
  541.     // render the image into the offscreen buffer
  542.     DrawPicture( thePicture, &theRect ) ;
  543.     
  544.     SetGWorld( savedPort, oldDevice ) ;
  545.     
  546.     // create the window
  547.     OffsetRect( &theRect, gStaggerPos.h, gStaggerPos.v) ;
  548.     gStaggerPos.h += 16 ;
  549.     gStaggerPos.v += 16 ;        // heh - should roll these around, but you wont 
  550.                                 // create more than a couple of windows, will you  :-)
  551.     
  552.     myWindowPtr = (MyWindowPtr)NewPtr ( sizeof( MyWindow ) );    
  553.                              
  554.     myWindowPtr  = (MyWindowPtr)NewCWindow( (Ptr)myWindowPtr, 
  555.                                             &theRect, 
  556.                                             "\pplayTime", 
  557.                                             true, 
  558.                                             documentProc, 
  559.                                             (WindowPtr)-1, 
  560.                                             true, 
  561.                                             (long)theNewWorld );    
  562.                                 
  563.     myWindowPtr->selRect = selectionRect ; 
  564.                 
  565.     // and if we set up the palette earlier assign it to the window                
  566.     if( thePictPalette != nil ) {
  567.         SetPalette ( (GrafPtr)myWindowPtr, thePictPalette, true );
  568.     }
  569.     
  570.     // make sure it is visible
  571.     ShowWindow( (GrafPtr)myWindowPtr ) ;
  572.     
  573.     SetGWorld( (CGrafPtr)myWindowPtr, nil ) ;
  574.     
  575.     // invalidate the content region of the window - we don't do any drawing to it here.
  576.     InvalRect ( &theRect );
  577.     
  578.     SetGWorld( savedPort, oldDevice ) ;
  579.     return noErr;
  580. }
  581.  
  582.  
  583.  
  584. void UpdateWindow( WindowPtr theWindow, Rect *refreshArea )
  585. {
  586.     GrafPtr            savedPort ;
  587.     Rect            copyRect ;
  588.     GWorldPtr        theNewWorld ;
  589.     PixMapHandle    offPixMap ;
  590.     
  591.     GetPort( &savedPort ) ;
  592.     SetPort( theWindow ) ;
  593.     
  594.     // get the GWorld from the window refcon
  595.     theNewWorld = (GWorldPtr)GetWRefCon ( theWindow );
  596.     offPixMap = GetGWorldPixMap( theNewWorld ) ;
  597.     
  598.     SectRect( refreshArea, &(**offPixMap).bounds, ©Rect ) ;
  599.     
  600.     (void) LockPixels( offPixMap ) ;
  601.     RGBForeColor( &kRGBBlack ) ;
  602.     RGBBackColor( &kRGBWhite ) ;
  603.     
  604.     CopyBits( &((GrafPtr)theNewWorld)->portBits,
  605.               &theWindow->portBits,
  606.               ©Rect,
  607.               ©Rect,
  608.               srcCopy,
  609.               nil ) ;
  610.               
  611.     (void) UnlockPixels( offPixMap ) ;
  612.     SetPort( savedPort ) ;
  613.  
  614. }
  615.  
  616. void TrackMouse( Point    Anchor, WindowPtr theWindow ) 
  617. {
  618.     Rect     theSelection = { 0, 0, 0, 0 };
  619.     Point    thePoint ;
  620.     
  621.  
  622.     SetPort( theWindow ) ;
  623.     
  624.     // get rid of the (possibly) old selection
  625.     if( !EmptyRect( &(((MyWindowPtr)theWindow)->selRect)) )
  626.         UpdateWindow( theWindow, CheckRect( &(((MyWindowPtr)theWindow)->selRect)) ) ;
  627.  
  628.     while(  StillDown () ) {
  629.  
  630.         // remove any old ants that were there before!!
  631.         if( !EmptyRect(    &theSelection ))
  632.             UpdateWindow( theWindow, CheckRect(&theSelection) ) ;
  633.             
  634.         GetMouse ( &thePoint );
  635.         
  636.         theSelection.top = Anchor.v ;
  637.         theSelection.left = Anchor.h ;
  638.         theSelection.bottom = thePoint.v ;
  639.         theSelection.right = thePoint.h ;
  640.         
  641.         AnimateMarquee( CheckRect(&theSelection), theWindow, true ) ;
  642.  
  643.     }
  644.     ((MyWindowPtr)theWindow)->selRect = theSelection ;
  645. }
  646.  
  647.  
  648. Rect *CheckRect( Rect *theRect )
  649. {
  650.     short    temp;
  651.  
  652.     if (theRect->top > theRect->bottom)        // Need to reverse top and bottom?
  653.     {
  654.         temp = theRect->top;
  655.         theRect->top = theRect->bottom;
  656.         theRect->bottom = temp;
  657.     }
  658.  
  659.     if (theRect->left > theRect->right)        // Need to reverse left and right?
  660.     {
  661.         temp = theRect->left;
  662.         theRect->left = theRect->right;
  663.         theRect->right = temp;
  664.     }
  665.     
  666.     return theRect;                            // This makes nested calls easier.
  667. }
  668.  
  669.  
  670. void    AnimateMarquee( Rect *theSelectionRect, WindowPtr whichWindow, Boolean mustDraw )
  671. {
  672.     #pragma unused (whichWindow)
  673.     short             index ;
  674.     unsigned char    lastPart ;
  675.  
  676.     if( mustDraw || TickCount() > gLastAnim + kTimeToAnimate ) {
  677.         if( !EmptyRect ( theSelectionRect ) ) {
  678.         
  679.             // we will have a Red marquee for the selection...
  680.             ForeColor( redColor ) ;
  681.             
  682.             // shuffle the bits in the pattern around
  683.             lastPart = gMarqueePattern.pat[7] ;
  684.             
  685.             for( index = 7; index > 0; --index ) 
  686.                 gMarqueePattern.pat[index] = gMarqueePattern.pat[ index-1 ] ;
  687.                 
  688.             gMarqueePattern.pat[0] = lastPart ;
  689.             PenNormal() ;
  690.             PenPat( &gMarqueePattern ) ;
  691.             FrameRect( theSelectionRect ) ;
  692.             gLastAnim = TickCount() ;
  693.             
  694.             // reset the port's color to black
  695.             ForeColor( blackColor ) ;
  696.  
  697.         }
  698.     }
  699. }